package network;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

//服务器
public class TcpEchoServer {
    private ServerSocket serverSocket = null;

    public TcpEchoServer(int port) throws IOException {
        serverSocket = new ServerSocket(port);
    }

    public void start() throws IOException {
        System.out.println("服务器启动!!!");
        //使用while循环来不断接受请求
        ExecutorService servicePool = Executors.newCachedThreadPool();
        while (true) {
            //在接受请求前要建立连接
            //用serverSocket中的accept方法
            //此方法会返回一个Socket对象,也就是clientSocket,利用clientSocket对象来和客户端进行交流
            Socket clientSocket = serverSocket.accept();
            //创建这个方法来具体处理这从连接
            servicePool.submit(()->{
                try {
                    processConnection(clientSocket);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
        }
    }

    private void processConnection(Socket clientSocket) throws IOException {
        //调用这个方法时说明已经建立了连接
        System.out.printf("[%s:%d]与客户端取得连接!\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
        //取得连接后,与客户端进行通信
        //利用io中的api来读取请求的数据
        try (InputStream inputStream = clientSocket.getInputStream();
             OutputStream outputStream = clientSocket.getOutputStream()){
            //1.读取请求,如果没有请求后就调出循环
            while (true) {
                Scanner scanner = new Scanner(inputStream);
                if (!scanner.hasNext()) {
                    System.out.printf("[%s:%d} 与客户端断开连接!\n",clientSocket.getInetAddress().toString(),
                            clientSocket.getPort());
                    break;
                }
                String request = scanner.next();
                //2.利用请求计算响应
                String response = process(request);
                //3.返回响应结果
                //利用 printWriter来写入,利用println方法是为了结果换行,方便对方读取
                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(response);
                //刷新缓冲区,为了确保响应已经发送
                printWriter.flush();
                //4.将处理的过程进行打印
                System.out.printf("[%s:%d] req : %s; resp : %s\n",clientSocket.getInetAddress().toString(),
                        clientSocket.getPort(),request,response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //每次客户端与服务器建立连接时,就会创建一个clientSocket对象,而该对象实质上是一个文件,存在于文件描述符表中
            //所以需要手动关闭,放在finally中是为了确保能够执行到这条代码
            //
            clientSocket.close();
        }
    }

    private String process(String request) {
        return request;
    }

    public static void main(String[] args) throws IOException {
        TcpEchoServer tcpEchoServer = new TcpEchoServer(9090);
        tcpEchoServer.start();
    }

}
